package hw2.cs236369.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import hw2.cs236369.extensions.Extender;
import hw2.cs236369.extensions.Predicate;
import hw2.cs236369.filtering.Filter;
import hw2.cs236369.interfaces.IAuthor;
import hw2.cs236369.interfaces.IDBFactory;
import hw2.cs236369.interfaces.IDBLP;
import hw2.cs236369.interfaces.IPaper;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;

import org.junit.Test;


public class FilterTests {

	/**
	 * A mock author
	 */
	private final static IAuthor	gal	= new IAuthor() {
											@Override
											public String getName() {
												return "Gal";
											}

											public String toString() {
												return getName();
											}

											public boolean equals(Object obj) {
												return obj.toString().equals("Gal");
											};
										};
	/**
	 * A mock author
	 */
	private final static IAuthor	gil	= new IAuthor() {
											@Override
											public String getName() {
												return "Gil";
											}

											public String toString() {
												return getName();
											}

											public boolean equals(Object obj) {
												return obj.toString().equals("Gil");
											};
										};
//										
//										private final static IAuthor	gross	= new IAuthor() {
//											@Override
//											public String getName() {
//												return "Gross";
//											}
//											
//											public String toString() {
//												return getName();
//											}
//											
//											public boolean equals(Object obj) {
//												return obj.toString().equals("Gross");
//											};
//										};

	/**
	 * A mock DLBP for testing
	 */
	private static interface MyIDBFactory extends IDBFactory {
		public IDBLP produce(final String regExp);
	}

	private MyIDBFactory	factory	= new MyIDBFactory() {
										@Override
										public IDBLP produce(String path, final String regExp) {
											return new IDBLP() {
												private final Collection<IPaper>	papers	= new LinkedList<IPaper>();
												private final Collection<IAuthor>	authors	= new LinkedList<IAuthor>();

												{
													authors.add(gal);
													authors.add(gil);
//													authors.add(gross);
													papers.add(new IPaper() {
														@Override
														public int getPublicationYear() {
															return 1990;
														}

														@Override
														public Collection<IAuthor> getAuthors() {
															return new LinkedList<IAuthor>(Arrays.asList(gil));
														}
													});
													papers.add(new IPaper() {
														@Override
														public int getPublicationYear() {
															return 1985;
														}

														@Override
														public Collection<IAuthor> getAuthors() {
															return new LinkedList<IAuthor>(Arrays.asList(gal));
														}
													});
													papers.add(new IPaper() {
														@Override
														public int getPublicationYear() {
															return 1995;
														}

														@Override
														public Collection<IAuthor> getAuthors() {
															return authors;
														}
													});
													papers.add(new IPaper() {
														@Override
														public int getPublicationYear() {
															return 1990;
														}

														@Override
														public Collection<IAuthor> getAuthors() {
															return new LinkedList<IAuthor>(Arrays.asList(gil));
														}
													});
												}

												@Override
												public Collection<IPaper> getPapers(final IAuthor author) {
													return Extender.where(papers, new Predicate<IPaper>() {
														@Override
														public Boolean calculate(IPaper element) {
															return Extender.contains(element.getAuthors(), author);
														}

													});
												}

												@Override
												public Collection<IAuthor> getFilteredAuthors() {
													return Extender.where(authors, new Predicate<IAuthor>() {
														@Override
														public Boolean calculate(IAuthor element) {
															return element.getName().matches(regExp);
														}

													});
												}
											};
										}

										@Override
										public IDBLP produce(String regExp) {
											return produce(null, regExp);
										}
									};

	@Test
	public void testFiltering() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("filtered authors size", 2, filter.getAuthors().size());
		filter = new Filter(factory.produce("Gal"));
		assertEquals("filtered authors size", 1, filter.getAuthors().size());
		assertTrue("filtered authors contains Gal", Extender.contains(filter.getAuthors(), gal));
	}

	@Test
	public void testGetPapers() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("total number of papers", 2, filter.getInfo(gal).getNumberOfPapers());
		assertEquals("total number of papers", 3, filter.getInfo(gil).getNumberOfPapers());
	}

	@Test
	public void testAverageNumberOfPapersPerYear() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("average number of papers", 2. / (95 - 85 + 1), filter.getInfo(gal).getAverageNumberOfPapersPerYear(), 0.000001);
		assertEquals("average number of papers", 3. / (95 - 90 + 1), filter.getInfo(gil).getAverageNumberOfPapersPerYear(), 0.000001);
	}

	@Test
	public void testMaxNumberOfPapersPerYear() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("max number of papers", 2, filter.getInfo(gil).getMaxNumberOfPapersPerYear());
		assertEquals("max number of papers", 1, filter.getInfo(gal).getMaxNumberOfPapersPerYear());
	}

	@Test
	public void testGetFirstPublication() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("year of first publication", 1985, filter.getInfo(gal).getFirstPublicationYear());
		assertEquals("year of first publication", 1990, filter.getInfo(gil).getFirstPublicationYear());
	}

	@Test
	public void testGetLastPublication() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("year of last publication", 1995, filter.getInfo(gal).getLastPublicationYear());
		assertEquals("year of last publication", 1995, filter.getInfo(gil).getLastPublicationYear());
	}

	@Test
	public void testAverageNumberOfCoAuthors() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("average number of coauthors", 0.5, filter.getInfo(gal).getAverageCoauthorsPerPaper(), 0.000001);
		assertEquals("average number of coauthors", 1. / 3, filter.getInfo(gil).getAverageCoauthorsPerPaper(), 0.000001);
	}

	@Test
	public void testTotalNumberOfCoAuthors() {
		Filter filter = new Filter(factory.produce(".*"));
		assertEquals("average number of coauthors", 1, filter.getInfo(gal).getTotalNumberOfCoauthors());
		assertEquals("average number of coauthors", 1, filter.getInfo(gil).getTotalNumberOfCoauthors());
	}
}
